/* Copyright (C) 2010 Fredrique Samuels, fredriquesamuels@gmail.com 

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "utils.h"

#include <windows.h>
#include <winbase.h>

#include <assert.h>

namespace tri {
namespace utils {

void sleep(long milli) {
    Sleep(milli);
}

bool is_pow2(int v){
    int n = 1;
    while (n <= v){
        if (v==n&&n!=1){
            return true;
        }
        n *= 2;
    };
    return false;
}

int next_pow2(int v){
    if(v<=0){
        return v;
    }
    int n = 1;
    while (n <= v){
        n = n * 2;
    }
    return n;
}

int string2int(const char * s ){
    return atoi(s);
}

float string2float(const char * s){
    return atof(s);
}

long string2long(const char * s){
    return atol(s);
}

std::string int2string(int i,int base){
    char buffer[20];
    itoa(i,buffer,base);
    return std::string(buffer);
}

timer::timer(){
    
    start_time = -1;
    end_time = -1;
    duration = 1.0;
    mode = CLOCK_MODE;
}

timer::~timer() {
    stop();
}


void timer::reset() {
    stop();
    start();
}

bool timer::start() {
    
    if (isRunning()){
        return false;
    }
    
    switch(mode){
    case CLOCK_MODE:
        start_time = clock();
        end_time = -1;
        break;
    case TIMER_MODE:
        start_time = clock();
        end_time = start_time + (int)( ((float)duration *1000)/(float)CLOCKS_PER_SEC );
        break;
    }
    
    return true;
}

void timer::stop(){
    start_time = end_time = 0;
}

double timer::getProgress() {
    if (isRunning() && mode == TIMER_MODE){
        double t = getElapsedTime();
        return t/duration;
    }
    
    return 1.0;
}

double timer::getElapsedTime(){
    
    if(isRunning()){
        switch(mode){
        case CLOCK_MODE:
            return (double)( clock()-start_time )/(double)CLOCKS_PER_SEC;
        case TIMER_MODE:
            double elapsed = (double)( clock()-start_time )/(double)CLOCKS_PER_SEC;
            if( elapsed > duration){
                start_time = end_time;
                return duration;
            }
            return elapsed;
        }
    }
    return 0;
}

bool timer::isRunning() {
    return !(start_time == end_time );
}

void timer::setDurationTime(double t) {
    if (isRunning()){
        return;
    }
    if (t < 0) {
        t = 0;
    }
    duration = t;
    start_time = end_time = 0;
    
}

void timer::setMode(int m){
    assert(  ( m == CLOCK_MODE || m==TIMER_MODE )  );
    mode =m;
}

int timer::getMode(){
    return mode;
}


void bubble_sort_list_4_uint32(unsigned int *a,int size,int hotIndex){
    
    assert(size%4==0);
    assert(hotIndex >= 0 && hotIndex <= 3);
    int c = size/4;
    
    for(int pass=1;pass<c;pass++){
            for(int i=0;i<4*(c-1);i+=4){
                if(a[i+hotIndex]>a[i+4+hotIndex]){
                    unsigned int hold1 = a[i];
                    unsigned int hold2 = a[i+1];
                    unsigned int hold3 = a[i+2];
                    unsigned int hold4 = a[i+3];
                    
                    a[i]= a[i+4];
                    a[i+1]= a[i+5];
                    a[i+2]= a[i+6];
                    a[i+3]= a[i+7];
                    
                    a[i+4] = hold1;
                    a[i+5] = hold2;
                    a[i+6] = hold3;
                    a[i+7] = hold4;
                                    
                }
            }
        }
}

void bubble_sort_list_4_uint32_decend(unsigned int *a,int size,int hotIndex){
    
    assert(size%4==0);
    assert(hotIndex >= 0 && hotIndex <= 3);
    int c = size/4;
    
    for(int pass=1;pass<c;pass++){
            for(int i=0;i<4*(c-1);i+=4){
                if(a[i+hotIndex]<a[i+4+hotIndex]){
                    unsigned int hold1 = a[i];
                    unsigned int hold2 = a[i+1];
                    unsigned int hold3 = a[i+2];
                    unsigned int hold4 = a[i+3];
                    
                    a[i]= a[i+4];
                    a[i+1]= a[i+5];
                    a[i+2]= a[i+6];
                    a[i+3]= a[i+7];
                    
                    a[i+4] = hold1;
                    a[i+5] = hold2;
                    a[i+6] = hold3;
                    a[i+7] = hold4;
                                    
                }
            }
        }
}

void fit_to_area(float src_w,float src_h,float dst_ar,float &dst_w, float &dst_h){

        if(src_w/dst_ar <= src_h){
            dst_w = src_w;
            dst_h = src_w/dst_ar;
        }else{
            dst_h = src_h;
            dst_w = src_h*dst_ar;
        }
}

}

}
